package doc

import (
	"encoding/json"
	"regexp"
	"strings"

	"github.com/go-chi/chi"
	"github.com/go-chi/docgen"
	"github.com/pkg/errors"
)

var rule = regexp.MustCompile(`@\w+`)

// Docs 文档数组
type Docs []Doc

// Document 接口文档内容
type Document string

// Doc 接口文档
type Doc struct {
	Method   string
	Pattern  string
	Document Document
}

// Parse 解析接口文档
func Parse(router chi.Router) (Docs, error) {
	doc, err := docgen.BuildDoc(router)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	docs := parseDocs(doc.Router.Routes)
	return docs, nil
}

// parseDocs parse doc routes
func parseDocs(routers docgen.DocRoutes) Docs {
	docs := make(Docs, 0)
	for _, v := range routers {
		if v.Router != nil {
			docs = append(docs, parseDocs(v.Router.Routes)...)
		}
		for method, header := range v.Handlers {
			docs = append(docs, Doc{
				Method:   method,
				Pattern:  v.Pattern,
				Document: Document(header.Comment),
			})
		}
	}
	return docs
}

// ScanStruct 解析成结构体
func (doc Document) ScanStruct(v interface{}) error {
	vs := doc.Docs()
	body, err := json.Marshal(vs)
	if err != nil {
		return errors.WithStack(err)
	}
	err = json.Unmarshal(body, &v)
	return errors.WithStack(err)
}

// Docs 转换成MAP数据格式
func (doc Document) Docs() map[string]string {
	body := []byte(doc)
	name := make([]byte, 0)
	docs := make([][]byte, 0)
	length := len(body) - 1

	for i, b := range body {
		if b == '@' {
			docs = append(docs, name)
			name = make([]byte, 0)
			name = append(name, '@')
		} else if b == '*' {
			continue
		} else if length == i {
			docs = append(docs, name)
		} else {
			name = append(name, b)
			continue
		}
	}

	values := make(map[string]string)
	for _, doc := range docs {
		if dt := rule.FindAll(doc, 1); len(dt) > 0 {
			k := strings.ToLower(strings.TrimPrefix(string(dt[0]), "@"))
			v := strings.TrimSpace(strings.TrimPrefix(string(doc), string(dt[0])))
			values[k] = v
		}
	}

	return values
}